package com.easylinkin.linkappapi.device.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.airconditioner.entity.ext.ImportData;
import com.easylinkin.linkappapi.common.constant.CommonConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.entity.DeviceRefAreaScope;
import com.easylinkin.linkappapi.device.entity.DeviceVoExt;
import com.easylinkin.linkappapi.device.mapper.DeviceMapper;
import com.easylinkin.linkappapi.device.mapper.DeviceRefAreaScopeMapper;
import com.easylinkin.linkappapi.device.service.DeviceRefAreaScopeService;
import com.easylinkin.linkappapi.function.mapper.LinkappFunctionMapper;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.space.entity.LinkappArea;
import com.easylinkin.linkappapi.space.entity.LinkappSpace;
import com.easylinkin.linkappapi.space.mapper.LinkappAreaMapper;
import com.easylinkin.linkappapi.space.mapper.LinkappSpaceMapper;
import org.hibernate.validator.constraints.Length;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;
import org.thymeleaf.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 设备关联功能关联作用区域 服务实现类
 * </p>
 *
 * @author TongJie
 * @since 2021-05-12
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class DeviceRefAreaScopeServiceImpl extends ServiceImpl<DeviceRefAreaScopeMapper, DeviceRefAreaScope> implements DeviceRefAreaScopeService {

    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    private LinkappAreaMapper linkappAreaMapper;

    @Resource
    private LinkappSpaceMapper linkappSpaceMapper;

    @Resource
    private DeviceMapper deviceMapper;

    @Resource
    private LinkappFunctionMapper linkappFunctionMapper;

    public String getCurrentUser() throws Exception {
        LinkappUser current = linkappUserContextProducer.getCurrent();
        if(current == null || StringUtils.isEmpty(current.getTenantId())){
            throw new Exception("未获取到当前用户信息");
        }
        return current.getTenantId();
    }

    @Override
    public IPage<Device> getDeviceListByAreaPathAndFunctionIdentifier(Page page, DeviceVoExt adpe) throws Exception {
        String tenantId = null;
        try{
            tenantId = getCurrentUser();
        }catch(Exception e){
            throw new Exception("获取当前用户信息异常");
        }
        DeviceRefAreaScope dras = new DeviceRefAreaScope();
        dras.setFunctionIdentifier(adpe.getFunctionIdentifier());
        dras.setTenantId(tenantId);
        dras.setAreaId(adpe.getId());
        dras.setAreaPath(adpe.getAreaPath());
        dras.setDeviceCode(adpe.getCode());
        List<Device> list = baseMapper.getDeviceListByAreaPathAndFunctionIdentifier(page, dras);
        setAreaName(list);
        page.setRecords(list);
        return page;
    }

    @Override
    public List<Device> getDeviceListByAreaPathAndFunctionIdentifier(DeviceVoExt adpe) throws Exception {
        String tenantId = null;
        try{
            tenantId = getCurrentUser();
        }catch(Exception e){
            throw new Exception("获取当前用户信息异常");
        }
        DeviceRefAreaScope dras = new DeviceRefAreaScope();
        dras.setFunctionIdentifier(adpe.getFunctionIdentifier());
        dras.setTenantId(tenantId);
        dras.setAreaId(adpe.getId());
        dras.setAreaPath(adpe.getAreaPath());
        dras.setDeviceCode(adpe.getCode());
        List<Device> list = baseMapper.getDeviceListByAreaPathAndFunctionIdentifier(dras);
        setAreaName(list);
        return list;
    }

    @Override
    public void bindAreaPathAndDevice(DeviceVoExt adp) throws Exception {
            Assert.notNull(adp.getId(), "区域id不能为空");
            Assert.notNull(adp.getAreaPath(), "区域路径不能为空");
            if(adp.getDeviceList() != null && !adp.getDeviceList().isEmpty()){
                String tenantId = null;
                try{
                    tenantId = getCurrentUser();
                }catch(Exception e){
                    throw new Exception("获取当前用户信息异常");
                }
                List<DeviceRefAreaScope> drasList = new ArrayList<DeviceRefAreaScope>();
                for (Device device:
                        adp.getDeviceList()) {
                    //先删除之前绑定的数据
                    Map<String, Object> deleteMap = new HashMap<String, Object>();
                    deleteMap.put("tenant_id", tenantId);
                    deleteMap.put("device_code", device.getCode());
                    deleteMap.put("function_identifier", adp.getFunctionIdentifier());
                    baseMapper.deleteByMap(deleteMap);

                    //重新绑定
                    DeviceRefAreaScope dras = new DeviceRefAreaScope();
                    dras.setTenantId(tenantId);
                    dras.setAreaId(adp.getId());
                    dras.setAreaPath(adp.getAreaPath());
                    dras.setDeviceCode(device.getCode());
                    dras.setFunctionIdentifier(adp.getFunctionIdentifier());
                    dras.setCreateTime(new Date());
                    dras.setUpdateTime(new Date());
                    drasList.add(dras);
                }
                baseMapper.batchInsert(drasList);

            }
    }

    /***
     * 一键绑定
     * @param adp
     */
    @Override
    public void oneKeySynBind(DeviceVoExt adp){
        if(adp.getDeviceList() == null || adp.getDeviceList().size()<=0){
            return;
        }
        String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
        List<String> deviceCodes = adp.getDeviceList().stream().map(Device::getCode).collect(Collectors.toList());
        int batchSize = 100;
        for (int idx = 0; idx < deviceCodes.size(); idx += batchSize) {
            List<String> batchDeviceCodes = deviceCodes.subList(idx, Math.min(deviceCodes.size(), idx + batchSize));
            Device queryDevice = new Device();
            queryDevice.setTenantId(tenantId);
            queryDevice.setDeviceCodeList(batchDeviceCodes);
            List<Device> deviceList = deviceMapper.selectDevices(queryDevice);
            if(deviceList == null ||deviceList.size()<=0){
                continue;
            }
            //组装数据
            Date date = new Date();
            List<DeviceRefAreaScope> drasList = deviceList.stream().map(device -> {
                //绑定
                DeviceRefAreaScope dras = new DeviceRefAreaScope();
                dras.setTenantId(tenantId);
                dras.setAreaId(device.getAreaId());
                dras.setAreaPath(device.getAreaPath());
                dras.setDeviceCode(device.getCode());
                dras.setFunctionIdentifier(adp.getFunctionIdentifier());
                dras.setCreateTime(date);
                dras.setUpdateTime(date);
                return dras;
            }).collect(Collectors.toList());

            if(drasList == null || drasList.size()<=0){
                continue;
            }
            baseMapper.batchInsert(drasList);
        }
    }

    @Override
    public void unbindDeviceAndFunctionIdentifier(DeviceVoExt adp) throws Exception {
            Assert.notNull(adp.getId(), "区域id不能为空");
            Assert.notNull(adp.getAreaPath(), "区域路径不能为空");
            if(adp.getDeviceList() != null && !adp.getDeviceList().isEmpty()){
                String tenantId = null;
                try{
                    tenantId = getCurrentUser();
                }catch(Exception e){
                    throw new Exception("获取当前用户信息异常");
                }
                List<String> codeList = new ArrayList<String>();
                for (Device device:
                        adp.getDeviceList()) {
//                    Integer bindDeviceCount = baseMapper.getBindDeviceCount(device.getCode());
//                    if(bindDeviceCount > 0){
//                        throw new IllegalArgumentException("已有设备在功能中使用, 无法解绑, 设备编码:" + device.getCode());
//                    }
                    codeList.add(device.getCode());
                }
                QueryWrapper qw = new QueryWrapper();
                qw.eq("tenant_id", tenantId);
                qw.eq("function_identifier", adp.getFunctionIdentifier());
                qw.in("device_code", codeList);
                baseMapper.delete(qw);
            }
    }

    @Override
    public String[] importDevice(MultipartFile file, String functionIdentifier) {

        String[] result = new String[2];
        InputStream inputStream = null;
        try {
            Map<String, String> headerMap = new HashMap<String, String>();
            headerMap.put("空间", "areaPath");
            headerMap.put("设备编码", "deviceCode");
            inputStream = file.getInputStream();

            List<ImportData> importDataList = ExcelTools.readExcel(inputStream, ExcelConstant.XLS, headerMap, ImportData.class, null);
            if(importDataList == null || importDataList.size() <= 0){
                result[0]= "1";
                result[1]= "无记录";
                return result;
            }
            String tenantId = null;
            try{
                tenantId = getCurrentUser();
            }catch(Exception e){
                throw new Exception("获取当前用户信息异常");
            }

            List<String> deviceCodeList = importDataList.stream().map(i->i.getDeviceCode()).collect(Collectors.toList());

            Object[] objects = checkDeviceTypeIsExistsFunction(deviceCodeList, functionIdentifier);
            if(!(Boolean)objects[0]){
                result[0]= "1";
                result[1]= (String)objects[1];
                return result;
            }


            for (ImportData iData:
                    importDataList) {
                if(!checkDeviceCodeIsExists(iData.getDeviceCode())){
                    result[0]= "1";
                    result[1]= "设备编码不存在:" + iData.getDeviceCode();
                    return result;
                }


                String  areaId = null;
                if(StringUtils.isEmpty(iData.getAreaPath()) ){
                    result[0]= "1";
                    result[1]= "空间名称:" + iData.getAreaPath() + "不能为空";
                    return result;
                }

                //适配空间或区域名称
                if(iData.getAreaPath().contains("/")){
                    iData.setAreaPath(iData.getAreaPath().replace("/", ":"));
                    LinkappArea linkappAreaInfo = getLinkappAreaInfo(iData.getAreaPath());
                    if(linkappAreaInfo == null){
                        result[0]= "1";
                        result[1]= "空间区域不存在:" + iData.getAreaPath();
                        return result;
                    }
                    areaId = linkappAreaInfo.getId();
                }else {
                    LinkappSpace linkappSpaceInfo = getLinkappSpaceInfo(iData.getAreaPath());
                    if(linkappSpaceInfo == null){
                        result[0]= "1";
                        result[1]= "空间区域不存在:" + iData.getAreaPath();
                        return result;
                    }
                    areaId = linkappSpaceInfo.getId();
                }

                Map<String, Object> deleteMap = new HashMap<String, Object>();
                deleteMap.put("tenant_id", tenantId);
                deleteMap.put("device_code", iData.getDeviceCode());
                deleteMap.put("function_identifier", functionIdentifier);
                baseMapper.deleteByMap(deleteMap);

                DeviceRefAreaScope dras = new DeviceRefAreaScope();
                dras.setTenantId(tenantId);
                dras.setAreaId(areaId);
                dras.setAreaPath(iData.getAreaPath());
                dras.setDeviceCode(iData.getDeviceCode());
                dras.setFunctionIdentifier(functionIdentifier);
                dras.setCreateTime(new Date());
                dras.setUpdateTime(new Date());
                baseMapper.insert(dras);
            }

            result[0]= "0";
            result[1]= "保存成功";
        } catch (Exception e) {
            e.printStackTrace();
            String[] result2 = new String[2];
            result[0]= "1";
            result[1]= "数据可能未识别到";
        }
        return result;
    }

    @Override
    public void exportAirDeviceTemplateFile(HttpServletRequest request, HttpServletResponse response) {
        String title = "设备分组导入模板";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);

            String keyValue = "空间:spaceName,设备编码:code";
            ExcelTools.exportExcelLqh(outputStream, keyValue, inits(), ExcelConstant.XLS,null);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            log.error("excel导出失败");
            throw new RuntimeException("excel导出失败！IOException异常");
        } catch (Exception e) {
            log.error("excel导出失败");
            throw new RuntimeException("excel导出失败！");
        }
    }

    public List<Device> inits(){
        return Arrays.asList(new Device()
                .setSpaceName("光谷步行街/意大利风情街/A区/A1")
                .setCode("625554633139"));
    }

    private LinkappArea getLinkappAreaInfo(String areaPath){//188

        LinkappArea la = new LinkappArea();
        la.setAreaPath(areaPath);
        List<LinkappArea> linkappAreasList = linkappAreaMapper.selectLinkappAreaList(la);

        if(linkappAreasList == null ||linkappAreasList.isEmpty()){
            return null;
        }else {
            return linkappAreasList.get(0);
        }
    }

    private LinkappSpace getLinkappSpaceInfo(String spaceName){//188

        LinkappSpace ls = new LinkappSpace();
        ls.setSpaceName(spaceName);
        List<LinkappSpace> linkappSapceList = linkappSpaceMapper.selectLinkappSpaceList(ls);

        if(linkappSapceList == null ||linkappSapceList.isEmpty()){
            return null;
        }else {
            return linkappSapceList.get(0);
        }
    }

    /**
     * 验证设备编码是否存在
     * @param deviceCode
     * @return
     */
    private Boolean checkDeviceCodeIsExists(String deviceCode){
        Boolean flag = true;
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("code", deviceCode);
        List<Device> deviceList = deviceMapper.selectByMap(paramMap);
        if(deviceList == null ||deviceList.isEmpty()){
            flag = false;
        }
        return flag;
    }

    /**
     * 验证设备的类型是否是该功能模块下的
     * @param deviceCodeList
     * @return
     */
    private Object[] checkDeviceTypeIsExistsFunction(List<String> deviceCodeList, String functionIdentifier){
        Object[] result = new Object[2];
        List<Device> deviceList = deviceMapper.selectDevices(new Device().setDeviceCodeList(deviceCodeList));

        StringBuilder notExistsDeviceCodeStr = new StringBuilder();
        List<Map<String, String>> functionDeviceTypeByIdentifier = linkappFunctionMapper.getFunacionDeviceTypeByIdentifier(functionIdentifier, linkappUserContextProducer.getNotNullCurrent().getTenantId());
        if(functionDeviceTypeByIdentifier == null || functionDeviceTypeByIdentifier.size()<=0){
            result[0] = false;
            result[1] = "该功能模块下未添加设备类型";
            return result;
        }
        List<String> deviceTypeIds=new ArrayList<>();
        functionDeviceTypeByIdentifier.forEach(m->{
            String deviceType = m.get("deviceType");
            if(org.apache.commons.lang3.StringUtils.isEmpty(deviceType)){
                return;
            }
            List<String> strings = JSONArray.parseArray(deviceType, String.class);
            if(strings == null || strings.size()<=0){
                return;
            }
            deviceTypeIds.addAll(strings);
        });
        
        deviceList.forEach(device ->{
            if(!deviceTypeIds.contains(device.getDeviceTypeId())){
                notExistsDeviceCodeStr.append(",").append(device.getCode());
            }
        });
        String errorMessage = notExistsDeviceCodeStr.toString();
        if(errorMessage != null && errorMessage.length() > 1){
            errorMessage = errorMessage.substring(1);
            result[0] = false;
            result[1] = "不符合功能下设备类型的编码：" + errorMessage;
            return result;
        }

        result[0] = true;
        result[1] = "success";
        return result;
    }


    private void setAreaName(List<Device> list) {
        if (list != null) {
            list.forEach(d -> {
                if (org.apache.commons.lang3.StringUtils.equals(d.getSpaceId(), d.getAreaId())) {
                    d.setAreaName(null);
                    d.setAreaPath(null);
                }
            });
        }
    }
}
